import { reactive, inject, ref, computed, watch, onScopeDispose } from 'vue'
import axios from 'axios'
import { CityBuildingLayer, LineLayer } from '@antv/l7'

export function useCityLayers() {
  // 响应式记录由本 composable 创建的图层
  const created = reactive({ building: null, roads: null })

  // 注入 mapScene（Map.vue 中应 provide({ map, scene })）
  const mapScene = inject('mapScene', null)
  const sceneRef = mapScene?.scene ?? null

  // 内部触发器：在 scene.addLayer/removeLayer 或 created 变化时 bump
  const tick = ref(0)
  const bump = () => (tick.value += 1)

  // 当 scene 就绪时，劫持 addLayer/removeLayer（只劫持一次）
  let restored = false
  const patchSceneLayerMethods = (s) => {
    if (!s || s.__layersPatched) return
    const origAdd = s.addLayer?.bind(s)
    const origRemove = s.removeLayer?.bind(s)

    if (typeof origAdd === 'function') {
      s.addLayer = function (...args) {
        const r = origAdd(...args)
        bump()
        return r
      }
    }
    if (typeof origRemove === 'function') {
      s.removeLayer = function (...args) {
        const r = origRemove(...args)
        bump()
        return r
      }
    }
    s.__layersPatched = true

    // 清理函数：恢复原方法（onScopeDispose 会在组件卸载/组合函数作用域结束时触发）
    onScopeDispose(() => {
      if (restored) return
      try {
        if (origAdd) s.addLayer = origAdd
        if (origRemove) s.removeLayer = origRemove
      } catch (e) { /* ignore */ }
      restored = true
    })
  }

  // 监听 sceneRef.value 就绪，立即 patch
  watch(
    () => sceneRef?.value,
    (s) => {
      if (s) patchSceneLayerMethods(s)
      bump()
    },
    { immediate: true }
  )

  // 也在 created 变化时触发刷新
  watch(
    created,
    () => bump(),
    { deep: true }
  )

  // 合并 scene.getLayers() 与 created，使用 tick 作为依赖强制更新
  const layerEntries = computed(() => {
    // 依赖 tick 保证外部调用 scene.addLayer/removeLayer 后能重算
    void tick.value
    const entries = []
    const s = sceneRef?.value
    if (s && typeof s.getLayers === 'function') {
      try {
        (s.getLayers() || []).forEach((l, i) => {
          const name = l.name ?? l.getName?.() ?? `layer-${i}`
          entries.push({ name, present: true, raw: l })
        })
      } catch (e) {
        // 忽略 getLayers 可能抛出的异常
      }
    }
    // 补上 created 中但未在 scene 中的自定义项
    Object.keys(created).forEach((k) => {
      if (!entries.some((e) => e.name === k)) {
        entries.push({ name: k, present: !!created[k], raw: created[k] })
      }
    })
    return entries
  })

  // 添加/删除图层（内部使用 sceneRef）
  async function addBuildingLayer() {
    const s = sceneRef?.value
    if (!s || created.building) return created.building
    const res = await axios.get('http://localhost:3001/Wuhan_buildings')
    const data = res.data
    const geo = {
      ...data,
      features: (data.features || []).map((f) => {
        const p = { ...(f.properties || {}) }
        p.height = Number(p.Elevation ?? p.elevation ?? 0)
        return { ...f, properties: p }
      }),
    }
    const layer = new CityBuildingLayer({ zIndex: 1, name: 'building' })
    if (typeof layer.source === 'function') {
      layer.source(geo, { parser: { type: 'geojson' } }).size('height').color('#aaaaff')
    } else if (typeof layer.setSource === 'function') {
      layer.setSource({ data: geo, parser: { type: 'geojson' } })
    }
    s.addLayer(layer)
    created.building = layer
    // bump 已由劫持 addLayer 触发，但为保险也手动 bump
    bump()
    return layer
  }

  async function addRoadsLayer() {
    const s = sceneRef?.value
    if (!s || created.roads) return created.roads
    if (typeof s.addImage === 'function') {
      try { s.addImage('arrow', '/道路箭头.svg') } catch (e) { }
    }
    const res = await axios.get('http://localhost:3001/Wuhan_roads')
    const layer = new LineLayer({ name: 'roads' })
    if (typeof layer.source === 'function') {
      layer.source(res.data).size(2).texture('arrow').color('rgb(22,119,255)')
    }
    s.addLayer(layer)
    created.roads = layer
    bump()
    return layer
  }

  function removeLayerByName(layerName) {
    const s = sceneRef?.value
    if (!s || !layerName) return
    const layer =
      (typeof s.getLayerByName === 'function' && s.getLayerByName(layerName)) ||
      (s.getLayers && s.getLayers().find((l) => (l.name === layerName || l.getName?.() === layerName)))
    if (layer) {
      try { s.removeLayer(layer) } catch (e) { /* ignore */ }
      if (created[layerName]) created[layerName] = null
      bump()
    }
  }

  return {
    addBuildingLayer,
    addRoadsLayer,
    removeLayerByName,
    created,
    layerEntries,
  }
}